package plus.easydo.starter.job.auto.call;

import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import plus.easydo.core.exception.ExceptionFactory;
import plus.easydo.starter.job.auto.model.ExecutorInfo;
import plus.easydo.starter.job.auto.model.SchedulerInfo;

import java.util.List;
import java.util.Objects;

/**
 * @author RaoYuan
 */
@Configuration
public class RemoteCallService implements RemoteCall {

    Logger log = LoggerFactory.getLogger(RemoteCallService.class);

    /** 执行器列表 */
    private static final String COOKIE = "Cookie";
    /** 执行器列表 */
    private static final String LOGIN = "/login";
    /**执行器列表 */
    private static final String EXECUTOR_LIST_PATH = "/jobgroup/save";
    /** 执行器注册 */
    private static final String EXECUTOR_REGISTER_PATH = "/jobgroup/pageList";
    /** 调度器列表 */
    private static final String SCHEDULER_LIST_PATH = "/jobinfo/pageList";
    /** 调度器注册 */
    private static final String SCHEDULER_REGISTER_PATH = "/jobinfo/add";
    /** 响应成功状态码 */
    private static final int SUCCESS_CODE = 200;
    /** 初始化restTemplate */
    private static final RestTemplate REST_TEMPLATE = new RestTemplate();

    @Override
    public String getCookie(String address, String username, String password) {
        try {
            ResponseEntity<String> responseEntity = REST_TEMPLATE.postForEntity(
                    address + LOGIN + "?" + "userName=" + username + "&password=" + password, null, String.class);
            JSONObject loginResponseBody = JSON.parseObject(responseEntity.getBody());
            Integer code = loginResponseBody.getInteger("code");
            // 校验返回结果是否正确
            Assert.isTrue(code == SUCCESS_CODE, loginResponseBody.getString("msg"));
            // 获取用户cookie信息
            HttpHeaders headers = responseEntity.getHeaders();
            log.debug("headers:{}", headers);
            List<String> headerList = headers.get("Set-Cookie");
            assert null != headerList && !headerList.isEmpty();
            return headerList.get(0).split(";")[0];
        } catch (Exception e) {
            log.warn("xxl-job登录异常,{}", e.getMessage());
            throw ExceptionFactory.baseException("xxl-job登录异常:" + e.getMessage());
        }
    }

    @Override
    public List<ExecutorInfo> executorList(String cookie, String address, String appname) {
        try {
            MultiValueMap<Object, Object> params = new LinkedMultiValueMap<>();
            if (CharSequenceUtil.isNotBlank(appname)) {
                params.add("appname", appname);
            }
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.set(COOKIE, cookie);
            return this.list(address + EXECUTOR_REGISTER_PATH, httpHeaders, params, ExecutorInfo.class);
        } catch (Exception e) {
            log.warn("xxl-job执行器列表查询异常,{}", e.getMessage());
            throw ExceptionFactory.baseException("xxl-job执行器列表查询异常:" + e.getMessage());
        }
    }

    @Override
    public void executorRegister(String cookie, String address, ExecutorInfo executorInfo) {
        try {
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.set(COOKIE, cookie);
            MultiValueMap<Object, Object> params = new LinkedMultiValueMap<>();
            params.add("appname", executorInfo.getAppname());
            params.add("title", executorInfo.getTitle());
            params.add("addressType", executorInfo.getAddressType());
            registerResCheck(address + EXECUTOR_LIST_PATH, httpHeaders, params);
        } catch (Exception e) {
            log.warn("xxl-job执行器自动注册异常,{}", e.getMessage());
            throw ExceptionFactory.baseException("执行器自动注册异常:" + e.getMessage());
        }
    }

    @Override
    public List<SchedulerInfo> schedulerList(String cookie, String address, Integer jobGroup) {
        try {
            MultiValueMap<Object, Object> params = new LinkedMultiValueMap<>();
            if (!Objects.isNull(jobGroup)) {
                params.add("jobGroup", jobGroup);
            }
            params.add("triggerStatus", -1);
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.set(COOKIE, cookie);
            return this.list(address + SCHEDULER_LIST_PATH, httpHeaders, params, SchedulerInfo.class);
        } catch (Exception e) {
            log.warn("xxl-job调度器列表获取异常,{}", e.getMessage());
            throw ExceptionFactory.baseException("调度器列表获取异常:" + e.getMessage());
        }
    }

    @Override
    public void schedulerRegister(String cookie, String address, SchedulerInfo schedulerInfo) {
        try {
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.set(COOKIE, cookie);
            MultiValueMap<Object, Object> params = new LinkedMultiValueMap<>();
            params.add("jobGroup", schedulerInfo.getJobGroup());
            params.add("scheduleType", schedulerInfo.getScheduleType());
            params.add("scheduleConf", schedulerInfo.getScheduleConf());
            params.add("cronGen_display", schedulerInfo.getCronGenDisplay());
            params.add("schedule_conf_CRON", schedulerInfo.getScheduleConfCron());
            params.add("schedule_conf_FIX_RATE", schedulerInfo.getScheduleConfFixRate());
            params.add("schedule_conf_FIX_DELAY", schedulerInfo.getScheduleConfFixDelay());
            params.add("jobDesc", schedulerInfo.getJobDesc());
            params.add("author", schedulerInfo.getAuthor());
            params.add("alarmEmail", schedulerInfo.getAlarmEmail());
            params.add("executorRouteStrategy", schedulerInfo.getExecutorRouteStrategy());
            params.add("executorHandler", schedulerInfo.getExecutorHandler());
            params.add("executorParam", schedulerInfo.getExecutorParam());
            params.add("executorBlockStrategy", schedulerInfo.getExecutorBlockStrategy());
            params.add("executorTimeout", schedulerInfo.getExecutorTimeout());
            params.add("executorFailRetryCount", schedulerInfo.getExecutorFailRetryCount());
            params.add("misfireStrategy", schedulerInfo.getMisfireStrategy());
            params.add("glueType", schedulerInfo.getGlueType());
            params.add("glueSource", schedulerInfo.getGlueSource());
            params.add("glueRemark", schedulerInfo.getGlueRemark());
            registerResCheck(address + SCHEDULER_REGISTER_PATH, httpHeaders, params);
        } catch (Exception e) {
            log.warn("xxl-job调度器自动注册异常,{}", e.getMessage());
            throw ExceptionFactory.baseException("调度器自动注册异常:" + e.getMessage());
        }
    }

    private <T> List<T> list(String url, HttpHeaders httpHeaders, MultiValueMap<Object, Object> params, Class<T> type) {
        HttpEntity<MultiValueMap<Object, Object>> requestEntity = new HttpEntity<>(params, httpHeaders);
        ResponseEntity<String> responseEntity = REST_TEMPLATE.postForEntity(url, requestEntity, String.class);
        JSONObject response = JSON.parseObject(responseEntity.getBody());
        JSONArray executorList = response.getJSONArray("data");
        return JSON.parseArray(executorList.toJSONString(), type);
    }

    private void registerResCheck(String url, HttpHeaders httpHeaders, MultiValueMap<Object, Object> params) {
        HttpEntity<MultiValueMap<Object, Object>> requestEntity = new HttpEntity<>(params, httpHeaders);
        ResponseEntity<String> responseEntity = REST_TEMPLATE.postForEntity(url, requestEntity, String.class);
        log.debug("register response:{}", responseEntity.getBody());
        JSONObject saveResponseBody = JSON.parseObject(responseEntity.getBody());
        // 校验返回结果是否正确
        Assert.isTrue(saveResponseBody.getInteger("code") == SUCCESS_CODE,
                saveResponseBody.getString("msg"));
    }

}
